﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using MaxLeaf.DB;
using MaxLeaf.Common;
using System.Data.SqlClient;


namespace MaxLeaf.DAL.K2K
{
    /// <summary>
    /// 分发基类,add/update/delete
    /// </summary>
    public class BaseDAL : IDALAction
    {
        public enum GetDataType
        {
            OrgData
            , DestKeyValue

        }
        //维护表名
        protected string strTableName = null;
        protected string   strUpdateFNumberTableName =null;
        //对应mkeymap使用的key
        protected string strMapKeyFieldName = "FitemID";
        //主key是独立key,还是和其他字段一起组成key
        protected bool blnMapKeyUseOtherKeyFieldsCond = false;
        //辅助key，就是多字段组成一个key
        protected Dictionary<string, object> dictOtherKeyFieldsCond = null;
        //原始数据和目标数据的辅助key值不一样时用
        protected Dictionary<string, object> dictDestOtherKeyFieldsCond = null;
        //实际数据库key
        protected string strDestRealKeyFieldName = "FNumber";
        //维护的字段，不包括key
        protected string strFieldNames = null;
        //新增时是否填写key值
        protected bool mblnNeedEditKeyValue = true;
        //mapkey是不是自增长的
        protected bool mblnIsIdentity = false;

        protected string strFItemClassID = null;

        /// <summary>
        /// 根据mapkey删除表数据
        /// 如果通过key找不到，表示不是通过程序分发的，忽略
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="strKeyValue"></param>
        public virtual void Delete(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, string strKeyValue)
        {
            DataTable dtKey = DAL_GetData(dbOrgK3Con, dbDestK3Con, (int)GetDataType.DestKeyValue, strKeyValue);
            if (dtKey.Rows.Count == 0)
            {
                return;
            }
            string strDestKeyValue = CvtFunc.ToString(dtKey.Rows[0]["DestKeyValue"]);

            Dictionary<string, object> dictCond = new Dictionary<string, object>() { { strMapKeyFieldName, strDestKeyValue } };
            if (blnMapKeyUseOtherKeyFieldsCond && dictOtherKeyFieldsCond != null)
            {
                foreach (KeyValuePair<string, object> tmp in dictOtherKeyFieldsCond)
                {
                    dictCond.Add(tmp.Key, tmp.Value);
                }
            }
            KeyValuePair<string, IDataParameter[]> kvp = dbDestK3Con.CreateCondParam(dictCond);
            string strSql = string.Format(@"delete from {0} where  {1}", strTableName, kvp.Key);
            dbDestK3Con.ExecuteSql(strSql, kvp.Value);
            if (strMapKeyFieldName.Equals("FitemID", StringComparison.InvariantCultureIgnoreCase) && GetMapTableName().Equals("t_item", StringComparison.InvariantCultureIgnoreCase))
            {
                //如果填了t_item表，也要一起删除
                kvp = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { strMapKeyFieldName, strDestKeyValue } });
                strSql = string.Format(@"delete from {0} where  {1}", "t_item", kvp.Key);
                dbDestK3Con.ExecuteSql(strSql, kvp.Value);
            }

            if (strTableName.Equals(GetMapTableName(), StringComparison.InvariantCultureIgnoreCase) || GetMapTableName().Equals("t_item", StringComparison.InvariantCultureIgnoreCase))
            {

                //删除mapkey
                KeyValuePair<string, IDataParameter[]> kvpParam = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { "TableName", GetMapTableName() }, { "DestKeyValue", strDestKeyValue } });
                dbDestK3Con.ExecuteSql(string.Format("delete from mKeyMap where {0}", kvpParam.Key), kvpParam.Value);
            }



        }


        /// <summary>
        /// Add没有单独处理,放在update
        /// 每次全部update
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="strKeyValue"></param>
        public virtual int Add(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, string strKeyValue)
        {
 

            return Update(dbOrgK3Con, dbDestK3Con, strKeyValue);

        }
        //判断原来有没有mapkey,已分发过
        const string TMPDESTKEYVALUE = "-10000";
        string strDestKeyValue = TMPDESTKEYVALUE;

        /// <summary>
        /// 每次全部update
        /// </summary>
        /// <param name="dbOrgK3Con">来源数据库</param>
        /// <param name="dbDestK3Con">目标数据库</param>
        /// <param name="strKeyValue"></param>
        public virtual int Update(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, string strKeyValue)
        {
            KeyValuePair<string, IDataParameter[]> kvpParam;
            string strOrgKeyValue = strKeyValue;
            string strUpdateFieldName = strFieldNames;

            #region 根据主帐套FitemID取得分账套FitemID
            DataTable dtKey = DAL_GetData(dbOrgK3Con, dbDestK3Con, (int)GetDataType.DestKeyValue, strKeyValue);

            strDestKeyValue = TMPDESTKEYVALUE;
            if (dtKey.Rows.Count != 0)
            {
                strDestKeyValue = CvtFunc.ToString(dtKey.Rows[0]["DestKeyValue"]);
            }
            #endregion 根据主帐套FitemID取得分账套FitemID

            kvpParam = CreateKeyParaCond(dbDestK3Con, strMapKeyFieldName, strDestKeyValue, true);

            DataTable dtData = dbDestK3Con.GetDataTable(
                string.Format("select {0} from {1} where {2}"
                        , strMapKeyFieldName + "," + strUpdateFieldName
                        , strTableName
                        , kvpParam.Key
                        )
                , kvpParam.Value
                );
            DataRow drData = null;
            LogStatus logStatus = LogStatus.Update;

            DataTable dtOrgData = DAL_GetData(dbOrgK3Con, dbDestK3Con, (int)GetDataType.OrgData, strOrgKeyValue);
            if (dtOrgData == null || dtOrgData.Rows.Count == 0)
            {
                return 0;
            }
            DataRow drOrgData = dtOrgData.Rows[0];


            //如果用keymap找不到,就用第2key(比如fnumber)再对应一次
            if (dtData.Rows.Count == 0 && !string.IsNullOrEmpty(strDestRealKeyFieldName))
            {
                kvpParam = CreateKeyParaCond(dbDestK3Con, strDestRealKeyFieldName, CvtFunc.ToString(drOrgData[strDestRealKeyFieldName]), true);

                dtData = dbDestK3Con.GetDataTable(
                    string.Format("select {0} from {1} where {2}"
                            , strMapKeyFieldName + "," + strUpdateFieldName
                            , strTableName
                            , kvpParam.Key
                            )
                    , kvpParam.Value
                    );
            }
            if (dtData.Rows.Count == 0)
            {
                //add
                strDestKeyValue = TMPDESTKEYVALUE;

                logStatus = LogStatus.Add;
                drData = dtData.NewRow();
                if (mblnNeedEditKeyValue)
                {
                    DAL_GetFieldData(dbOrgK3Con, dbDestK3Con, strMapKeyFieldName, drOrgData, drData);

                    if ((strUpdateFieldName + ",").IndexOf(strMapKeyFieldName + ",", StringComparison.InvariantCultureIgnoreCase) < 0)
                    {
                        strUpdateFieldName = strMapKeyFieldName + "," + strUpdateFieldName;
                    }
                }


                if (dictDestOtherKeyFieldsCond != null)
                {
                    foreach (KeyValuePair<string, object> tmp in dictDestOtherKeyFieldsCond)
                    {
                        drData[tmp.Key] = tmp.Value;
                        if ((strUpdateFieldName + ",").IndexOf(tmp.Key + ",", StringComparison.InvariantCultureIgnoreCase) < 0)
                        {
                            strUpdateFieldName = tmp.Key + "," + strUpdateFieldName;
                        }
                    }
                }
                else if (dictOtherKeyFieldsCond != null)
                {
                    foreach (KeyValuePair<string, object> tmp in dictOtherKeyFieldsCond)
                    {
                        drData[tmp.Key] = tmp.Value;
                        if ((strUpdateFieldName + ",").IndexOf(tmp.Key + ",", StringComparison.InvariantCultureIgnoreCase) < 0)
                        {
                            strUpdateFieldName = tmp.Key + "," + strUpdateFieldName;
                        }
                    }
                }
            }
            else
            {
                drData = dtData.Rows[0];
            }

            //其他字段填值
            string[] arrFieldName = strUpdateFieldName.Split(',');
            foreach (string strField in arrFieldName)
            {
                DAL_GetFieldData(dbOrgK3Con, dbDestK3Con, strField, drOrgData, drData);
            }

            Update_Before(dbOrgK3Con, dbDestK3Con, drOrgData, drData);

            //add or update
            KeyValuePair<string, IDataParameter[]> kvp = dbDestK3Con.CreateParamSql(strUpdateFieldName, strTableName, drData, logStatus, strMapKeyFieldName);
            string strIdentity = dbDestK3Con.GetValue(kvp.Key, kvp.Value);
            if (mblnIsIdentity && logStatus == LogStatus.Add)
            {
                drData[strMapKeyFieldName] = strIdentity;
            }
            if (strDestKeyValue.Equals(TMPDESTKEYVALUE))
            {
                //得到mapkey,保存
                if (!string.IsNullOrEmpty(strDestRealKeyFieldName))
                {
                    kvpParam = CreateKeyParaCond(dbDestK3Con, strDestRealKeyFieldName, CvtFunc.ToString(drData[strDestRealKeyFieldName]), true);

                    dtData = dbDestK3Con.GetDataTable(
                        string.Format("select {0} from {1} where {2}"
                                , strMapKeyFieldName
                                , strTableName
                                , kvpParam.Key
                                )
                        , kvpParam.Value
                        );
                    strDestKeyValue = CvtFunc.ToString(dtData.Rows[0][strMapKeyFieldName]);
                }
                else
                {
                    strDestKeyValue = CvtFunc.ToString(drData[strMapKeyFieldName]);
                }
                SaveKeyMap(dbDestK3Con, strOrgKeyValue, strDestKeyValue);
            }


            UpdateOtherData(dbOrgK3Con, dbDestK3Con, drOrgData, drData);

            return CvtFunc.ToInt(drData[strMapKeyFieldName]);

        }

        protected virtual void Update_Before(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, DataRow drOrgData, DataRow drData)
        {
            if(drData.Table.Columns.Contains("FitemID"))
            {
            Update_t_Item(dbDestK3Con, CvtFunc.ToString(drData["FitemID"]), CvtFunc.ToString(drData["FNumber"]), CvtFunc.ToString(drData["Fname"]));
            }
        }

        protected virtual void Update_t_Item(DBAccess dbDestK3Con, string strFItemID, string strFnumber, string strFName)
        {
            string strSql = string.Empty;
            KeyValuePair<string, IDataParameter[]> kvp = new KeyValuePair<string, IDataParameter[]>();

            if (strFItemID.Length == 0) return;
            if (CvtFunc.ToInt(strFItemID) <= 0) throw new MaxLeafException(string.Format("FItemID is {0}",strFItemID));

            string strOldFNumber = dbDestK3Con.GetValue("select fnumber from t_Item Where  FitemID=@FitemID  and FItemClassID=@FItemClassID", new SqlParameter[] { new SqlParameter("@FitemID", strFItemID), new SqlParameter("@FItemClassID", strFItemClassID) });

            strSql = "Update t_Item Set   Fparentid=@Fparentid,Fnumber=@Fnumber,FName=@FName,FShortNumber=@FShortNumber,FFullNumber=@Fnumber Where  FitemID=@FitemID and FItemClassID=@FItemClassID";
            kvp = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { "Fparentid", GetFParentId(dbDestK3Con, strFnumber) }, { "Fnumber", strFnumber }, { "FName", strFName }, { "FShortNumber", GetShortNumber(strFnumber) }, { "FitemID", strFItemID }, { "FItemClassID", strFItemClassID } });
            dbDestK3Con.ExecuteSql(strSql, kvp.Value);

            if (!strOldFNumber.Equals(strFnumber, StringComparison.InvariantCultureIgnoreCase))
            {
                if (!strOldFNumber.Split('.').Length.Equals(strFnumber.Split('.').Length))
                {
                    throw new MaxLeafException(string.Format("Cannot change fnumber {0} to {1}", strOldFNumber, strFnumber));
                }

                strSql = "Update t_Item Set FNumber = {fn INSERT(FNumber, 1, @Len, @FNumber)},FFullNumber = {fn INSERT(FNumber, 1, @Len, @FNumber)} Where FNumber Like @OldFNumber AND FItemClassID = @FItemClassID";
                kvp = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { "Len", strFnumber.Length }, { "Fnumber", strFnumber }, { "OldFNumber", strOldFNumber + ".%" }, { "FItemClassID", strFItemClassID } });
                dbDestK3Con.ExecuteSql(strSql, kvp.Value);


                if (!(strUpdateFNumberTableName == null || strUpdateFNumberTableName.Length == 0))
                {
                    strSql = string.Format("UPDATE {0} Set FNumber =i.F1  From ( Select FNumber F1,FItemID FID1,FParentID FPID1 From t_Item Where FNumber Like @FNumber AND FItemClassID =  @FItemClassID ) i Where FItemID=i.FID1 "
                        , strUpdateFNumberTableName
                        );
                    kvp = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { "FNumber", strFnumber + ".%" }, { "FItemClassID", strFItemClassID } });
                    dbDestK3Con.ExecuteSql(strSql, kvp.Value);
                }
            }

        }

         

        private string GetFParentId(DBAccess dbDestK3Con, string strFnumber)
        {
            string[] arrFnumber = strFnumber.Split('.');
            string strParentFNumber = string.Join(".", arrFnumber, 0, arrFnumber.Length - 1);
            if (strParentFNumber.Length == 0)
            {
                return "0";
            }

            return dbDestK3Con.GetValue("select FitemID from t_item where fnumber=@fnumber and FItemClassID=@FItemClassID", new SqlParameter[] { new SqlParameter("@fnumber", strParentFNumber), new SqlParameter("@FItemClassID", strFItemClassID) });
        }

        protected void SaveKeyMap(DBAccess dbDestK3Con, string strOrgKeyValue, string strDestKeyValue)
        {
            string strSql = @"if not exists(select * from mKeyMap where TableName=@TableName and OrgKeyValue=@OrgKeyValue)
            begin
                insert into mKeyMap(TableName,OrgKeyValue,DestKeyValue) 
                values(@TableName,@OrgKeyValue,@DestKeyValue)
            end ";
            KeyValuePair<string, IDataParameter[]> kvpMap = dbDestK3Con.CreateCondParam(new Dictionary<string, object> {
                { "TableName", GetMapTableName() }
                , { "OrgKeyValue", strOrgKeyValue }
                , { "DestKeyValue", strDestKeyValue }
            });
            dbDestK3Con.ExecuteSql(strSql, kvpMap.Value);
        }


        /// <summary>
        /// 更新完主数据，再更新其他数据
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="drOrgData"></param>
        /// <param name="drData"></param>
        protected virtual void UpdateOtherData(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, DataRow drOrgData, DataRow drData)
        {

        }

        /// <summary>
        /// 根据主key+辅助key建条件
        /// </summary>
        /// <param name="dbDestK3Con"></param>
        /// <param name="strKeyFieldName"></param>
        /// <param name="strDestKeyValue"></param>
        /// <param name="blnDest"></param>
        /// <returns></returns>
        private KeyValuePair<string, IDataParameter[]> CreateKeyParaCond(DBAccess dbDestK3Con, string strKeyFieldName, string strDestKeyValue, bool blnDest)
        {
            Dictionary<string, object> dictCond = new Dictionary<string, object>() { { strKeyFieldName, strDestKeyValue } };
            if (!blnMapKeyUseOtherKeyFieldsCond && strKeyFieldName.Equals(strMapKeyFieldName, StringComparison.InvariantCultureIgnoreCase))
            {
            }
            else
            {
                if (blnDest && dictDestOtherKeyFieldsCond != null)
                {
                    foreach (KeyValuePair<string, object> tmp in dictDestOtherKeyFieldsCond)
                    {
                        dictCond.Add(tmp.Key, tmp.Value);
                    }
                }
                else if (dictOtherKeyFieldsCond != null)
                {
                    foreach (KeyValuePair<string, object> tmp in dictOtherKeyFieldsCond)
                    {
                        dictCond.Add(tmp.Key, tmp.Value);
                    }
                }
            }
            KeyValuePair<string, IDataParameter[]> kvp = dbDestK3Con.CreateCondParam(dictCond);
            return kvp;
        }

        /// <summary>
        /// 根据FielName赋值
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="strFieldName"></param>
        /// <param name="drOrgData"></param>
        /// <param name="drDestData"></param>
        protected virtual void DAL_GetFieldData(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, string strFieldName, DataRow drOrgData, DataRow drDestData)
        {
            drDestData[strFieldName] = drOrgData[strFieldName];
        }

        /// <summary>
        /// 获取数据
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="intdataType"></param>
        /// <param name="objParam"></param>
        /// <returns></returns>
        protected virtual DataTable DAL_GetData(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, int intdataType, object objParam)
        {

            GetDataType dataType = (GetDataType)intdataType;
            if (dataType == GetDataType.DestKeyValue)
            {
                return GetDestKeyValue(dbOrgK3Con, dbDestK3Con, CvtFunc.ToString(objParam));
            }
            else if (dataType == GetDataType.OrgData)
            {
                return GetOrgData(dbOrgK3Con, CvtFunc.ToString(objParam));
            }


            throw new MaxLeafException(string.Format("GetData {0} 没注册", intdataType));

        }

        /// <summary>
        /// 获取来源表数据
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="strOrgKeyValue"></param>
        /// <returns></returns>
        private DataTable GetOrgData(DBAccess dbOrgK3Con, string strOrgKeyValue)
        {

            KeyValuePair<string, IDataParameter[]> kvpParam = CreateKeyParaCond(dbOrgK3Con, strMapKeyFieldName, strOrgKeyValue, false);

            DataTable dtOrgData = dbOrgK3Con.GetDataTable(
             string.Format("select {0} from {1} where {2}"
                     , "*"
                     , strTableName
                     , kvpParam.Key
                     )
             , kvpParam.Value
             );


            return dtOrgData;
        }

        /// <summary>
        /// mapkey
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="strOrgKeyValue"></param>
        /// <returns></returns>
        private DataTable GetDestKeyValue(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, string strOrgKeyValue)
        {

            return dbDestK3Con.GetTableData("mKeyMap", new Dictionary<string, object>() { { "TableName", GetMapTableName() }, { "OrgKeyValue", strOrgKeyValue } }, "DestKeyValue");
        }

        /// <summary>
        /// 如果mapkeyname=FitemID,就都用t_item表
        /// </summary>
        /// <returns></returns>
        protected string GetMapTableName()
        {
            string strMapTableName = strTableName;
            if (strMapKeyFieldName.Equals("FitemID", StringComparison.InvariantCultureIgnoreCase))
            {
                strMapTableName = "t_Item";
            }
            return strMapTableName;
        }

        /// <summary>
        /// 取得mapkey,没有找到就先强制分发一次
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="strOrgKeyValue"></param>
        /// <returns></returns>
        public virtual string GetDestMapKeyValue(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, string strOrgKeyValue)
        {
            if (dbDestK3Con.ServerMasterDB)
            {
                //如果是主帐套，就是原始值
                return strOrgKeyValue;
            }
            KeyValuePair<string, IDataParameter[]> kvp = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { "TableName", GetMapTableName() }, { "OrgKeyValue", strOrgKeyValue } });
            string strSql = string.Format("select DestKeyValue from mkeymap where {0}", kvp.Key);

            string strDestMapKeyValue = dbDestK3Con.GetValue(strSql, kvp.Value);
            if (strDestMapKeyValue.Length > 0)
            {
                return strDestMapKeyValue;
            }

            Update(dbOrgK3Con, dbDestK3Con, strOrgKeyValue);

            kvp = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { "TableName", GetMapTableName() }, { "OrgKeyValue", strOrgKeyValue } });
            return dbDestK3Con.GetValue(strSql, kvp.Value);
        }


        /// <summary>
        /// 取得mapkey,没有找到就先强制分发一次
        /// </summary>
        /// <param name="dbOrgK3Con"></param>
        /// <param name="dbDestK3Con"></param>
        /// <param name="strOrgKeyValue"></param>
        /// <returns></returns>
        public virtual string GetOrgMapKeyValue(DBAccess dbOrgK3Con, DBAccess dbDestK3Con, string strDestKeyValue)
        {
            if (dbDestK3Con.ServerMasterDB)
            {
                //如果是主帐套，就是原始值
                return strDestKeyValue;
            }

            KeyValuePair<string, IDataParameter[]> kvp = dbDestK3Con.CreateCondParam(new Dictionary<string, object>() { { "TableName", GetMapTableName() }, { "DestKeyValue", strDestKeyValue } });
            string strSql = string.Format("select OrgKeyValue from mkeymap where {0}", kvp.Key);

            return dbDestK3Con.GetValue(strSql, kvp.Value);

        }

        protected string GetShortNumber(string strFNumber)
        {
            string[] arr = strFNumber.Split('.');
            return arr[arr.Length - 1];
        }
    }
}
